package com.canaan.business.service.bill.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.canaan.business.common.enums.basic.WhetherEnum;
import com.canaan.business.common.enums.basic.YNEnum;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.InStockOrderTypeEnum;
import com.canaan.business.common.enums.quality.QualityTypeEnum;
import com.canaan.business.domain.basic.ProductQualityConfig;
import com.canaan.business.domain.basic.WmsBaseSupplier;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.bill.ReceiveProductBill;
import com.canaan.business.domain.bill.ReceiveProductBillCheck;
import com.canaan.business.domain.bill.ReceiveProductBillDetail;
import com.canaan.business.domain.inOutStock.WmsInStockDetailOrder;
import com.canaan.business.domain.inOutStock.WmsInStockOrder;
import com.canaan.business.domain.quality.ProductQualityItem;
import com.canaan.business.domain.vo.ReceiveBillForPrintVO;
import com.canaan.business.domain.vo.ReceiveProductBillExportCheckVo;
import com.canaan.business.domain.vo.ReceiveProductBillExportVo;
import com.canaan.business.domain.vo.ReceiveProductBillVo;
import com.canaan.business.mapper.bill.ReceiveProductBillMapper;
import com.canaan.business.service.basic.IProductQualityConfigService;
import com.canaan.business.service.basic.IWmsBaseSupplierService;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.bill.IReceiveProductBillCheckService;
import com.canaan.business.service.bill.IReceiveProductBillDetailService;
import com.canaan.business.service.bill.IReceiveProductBillService;
import com.canaan.business.service.inOutStock.IWmsInStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.business.service.quality.IProductQualityItemService;
import com.canaan.business.service.storehouse.IWmsBarcodeRecordService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.apache.commons.compress.utils.Sets;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 收货单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-02-01
 */
@Service
public class ReceiveProductBillServiceImpl implements IReceiveProductBillService {
    @Resource
    private ReceiveProductBillMapper receiveProductBillMapper;
    @Resource
    private IWmsBaseSupplierService supplierService;
    @Resource
    private IWmsProductService productService;
    @Resource
    private IWmsBarcodeRecordService wmsBatchRecordService;
    @Resource
    private IReceiveProductBillDetailService receiveProductBillDetailService;
    @Resource
    private IReceiveProductBillCheckService receiveProductBillCheckService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IWmsInStockDetailOrderService wmsInStockDetailOrderService;
    @Resource
    private IProductQualityItemService qualityItemService;
    @Resource
    private IProductQualityConfigService qualityConfigService;

    /**
     * 查询收货单
     *
     * @param id 收货单主键
     * @return 收货单
     */
    @Override
    public ReceiveProductBill selectReceiveProductBillById(Long id) {
        ReceiveProductBill bill = receiveProductBillMapper.selectReceiveProductBillById(id);
        ReceiveProductBillCheck query = new ReceiveProductBillCheck();
        query.setBillNo(bill.getNo());
        List<ReceiveProductBillCheck> list = receiveProductBillCheckService.selectReceiveProductBillCheckList(query);
        if (CollectionUtil.isNotEmpty(list)) {
            bill.setCheckTotalQty(list.stream().mapToLong(e -> e.getQty()).sum());
        }
        return bill;
    }

    /**
     * 查询收货单列表
     *
     * @param receiveProductBill 收货单
     * @return 收货单
     */
    @Override
    public List<ReceiveProductBill> selectReceiveProductBillList(ReceiveProductBill receiveProductBill) {
        List<ReceiveProductBill> list = receiveProductBillMapper.selectReceiveProductBillList(receiveProductBill);
        if (CollectionUtil.isNotEmpty(list)) {
            list.stream().forEach(e -> {
                ReceiveProductBillCheck query = new ReceiveProductBillCheck();
                query.setBillNo(e.getNo());
                List<ReceiveProductBillCheck> checkkList = receiveProductBillCheckService.selectReceiveProductBillCheckList(query);
                if (CollectionUtil.isNotEmpty(checkkList)) {
                    e.setCheckTotalQty(checkkList.stream().mapToLong(i -> i.getQty()).sum());
                }
            });
        }
        return list;
    }

    /**
     * 新增收货单
     *
     * @param receiveProductBill 收货单
     * @return 结果
     */
    @Override
    public int insertReceiveProductBill(ReceiveProductBill receiveProductBill) {
        if (StringUtils.isBlank(receiveProductBill.getNo())) {
            receiveProductBill.setNo(PrefixConstants.RECEIPT + TableNoUtil.getNo(ReceiveProductBill.class));
        }
        if(StringUtils.isEmpty(receiveProductBill.getCreateBy())){
            receiveProductBill.setCreateBy(SecurityUtils.getUsername());
        }
        receiveProductBill.setCreateTime(DateUtils.getNowDate());
        receiveProductBill.setStatus(InOrderStatusEnum.NEW.getCode());
        return receiveProductBillMapper.insertReceiveProductBill(receiveProductBill);
    }

    /**
     * 批量新增收货单
     *
     * @param receiveProductBillList 收货单列表
     * @return 结果
     */
    @Override
    public int batchInsertReceiveProductBill(List<ReceiveProductBill> receiveProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ReceiveProductBill receiveProductBill : receiveProductBillList) {
            if (StringUtils.isBlank(receiveProductBill.getNo())) {
                receiveProductBill.setNo(TableNoUtil.getNo(ReceiveProductBill.class));
            }
            receiveProductBill.setCreateBy(username);
            receiveProductBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i = 0; i < receiveProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > receiveProductBillList.size()) {
                endIndex = receiveProductBillList.size();
            }
            insertNum = insertNum + receiveProductBillMapper.batchInsertReceiveProductBill(receiveProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改收货单
     *
     * @param receiveProductBill 收货单
     * @return 结果
     */
    @Override
    public int updateReceiveProductBill(ReceiveProductBill receiveProductBill) {
        try {
            if(StringUtils.isEmpty(receiveProductBill.getUpdateBy())) {
                receiveProductBill.setUpdateBy(SecurityUtils.getUsername());
            }
        } catch (Exception e) {
            receiveProductBill.setUpdateBy("ERP");
        }
        receiveProductBill.setUpdateTime(DateUtils.getNowDate());
        return receiveProductBillMapper.updateReceiveProductBill(receiveProductBill);
    }

    /**
     * 批量修改收货单
     *
     * @param receiveProductBillList 收货单列表
     * @return 结果
     */
    @Override
    public int batchUpdateReceiveProductBill(List<ReceiveProductBill> receiveProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ReceiveProductBill receiveProductBill : receiveProductBillList) {
            receiveProductBill.setUpdateBy(username);
            receiveProductBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i = 0; i < receiveProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > receiveProductBillList.size()) {
                endIndex = receiveProductBillList.size();
            }
            updateNum = updateNum + receiveProductBillMapper.batchUpdateReceiveProductBill(receiveProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除收货单
     *
     * @param ids 需要删除的收货单主键集合
     * @return 结果
     */
    @Override
    public int deleteReceiveProductBillByIds(Long[] ids) {
        ReceiveProductBill bill = new ReceiveProductBill();
        bill.setIds(CollUtil.toList(ids));
        List<ReceiveProductBill> billList = this.selectReceiveProductBillList(bill);
        billList.stream().forEach(e -> {
            if (!InOrderStatusEnum.NEW.getCode().equals(e.getStatus())) {
                throw new ServiceException(InOrderStatusEnum.NEW.getMessage() + "状态下才允许删");
            }
        });
        return receiveProductBillMapper.deleteReceiveProductBillByIds(ids);
    }

    /**
     * 删除收货单信息
     *
     * @param id 收货单主键
     * @return 结果
     */
    @Override
    public int deleteReceiveProductBillById(Long id) {
        return receiveProductBillMapper.deleteReceiveProductBillById(id);
    }

    /**
     * 查询收货单
     *
     * @param no 编号
     * @return 收货单
     */
    @Override
    public ReceiveProductBill selectReceiveProductBillByNo(String no) {
        return receiveProductBillMapper.selectReceiveProductBillByNo(no);
    }

    /**
     * 批量删除收货单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteReceiveProductBillByNos(String[] nos) {
        return receiveProductBillMapper.deleteReceiveProductBillByNos(nos);
    }

    /**
     * 删除收货单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteReceiveProductBillByNo(String no) {
        return receiveProductBillMapper.deleteReceiveProductBillByNo(no);
    }

    @Override
    public List<ReceiveProductBillExportVo> exportList(ReceiveProductBill receiveProductBill) {
        return receiveProductBillMapper.exportList(receiveProductBill);
    }

    @Override
    public List<ReceiveProductBillExportCheckVo> exportCheckList(ReceiveProductBill receiveProductBill) {
        return receiveProductBillMapper.exportCheckList(receiveProductBill);
    }

    @Override
    public List<String> importExcel(List<ReceiveProductBillExportVo> list) {
        List<String> errList = new ArrayList<>();
        Map<String, List<ReceiveProductBillExportVo>> groupMap = list.stream().collect(Collectors.groupingBy(e -> e.getSupplierName() + ":" + e.getPurchaseOrderNo()));
        Set<String> groupKeys = groupMap.keySet();
        for (String groupKey : groupKeys) {
            String[] split = groupKey.split(":");
            String customerName = split[0];
            String purchaseOrderNo = split[1];
            List<ReceiveProductBillExportVo> salesRefundBillExportVos = groupMap.get(groupKey);
            WmsBaseSupplier wmsBaseSupplier = supplierService.selectWmsBaseSupplierByName(customerName);
            if (wmsBaseSupplier == null) {
                errList.add("无效供应商名称：" + wmsBaseSupplier.getName());
                continue;
            }
            ReceiveProductBill receiveProductBill = new ReceiveProductBill();
            receiveProductBill.setSupplierNo(wmsBaseSupplier.getNo());
            receiveProductBill.setSupplierName(wmsBaseSupplier.getName());
            receiveProductBill.setPurchaseOrderNo(purchaseOrderNo);
            receiveProductBill.setTotalQty(salesRefundBillExportVos.stream().filter(e -> e.getQty() != null).mapToLong(e -> e.getQty()).sum());
            this.insertReceiveProductBill(receiveProductBill);

            List<ReceiveProductBillDetail> details = new ArrayList<>();
            for (ReceiveProductBillExportVo receiveProductBillExportVo : salesRefundBillExportVos) {
                if (!StringUtils.isEmpty(receiveProductBillExportVo.getProductNo())) {
                    ReceiveProductBillDetail receiveProductBillDetail = new ReceiveProductBillDetail();
                    receiveProductBillDetail.setBillNo(receiveProductBill.getNo());
                    receiveProductBillDetail.setQty(receiveProductBillExportVo.getQty());
                    receiveProductBillDetail.setProductNo(receiveProductBillExportVo.getProductNo());
                    WmsProduct wmsProduct = productService.selectWmsProductByProductNo(receiveProductBillExportVo.getProductNo());
                    if (wmsProduct == null) {
                        errList.add("无效物料编码：" + wmsProduct.getProductNo());
                        continue;
                    }
                    receiveProductBillDetail.setProductName(wmsProduct.getProductName());
                    receiveProductBillDetail.setProductUnit(wmsProduct.getCompany());
                    details.add(receiveProductBillDetail);
                }
            }
            if (CollUtil.isNotEmpty(details)) {
                receiveProductBillDetailService.batchInsertReceiveProductBillDetail(details);
            }
        }
        return errList;
    }


    /**
     * 完成收货
     *
     * @param params 收货编号和清单列表
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int complete(ReceiveProductBillVo params) {
        if (params == null) {
            throw new ServiceException("数据为空");
        }
        ReceiveProductBill bill = this.receiveProductBillMapper.selectReceiveProductBillByNo(params.getNo());
        if (bill == null) {
            throw new ServiceException("找不到收货单");
        }
        //取到货清单
        ReceiveProductBillCheck check = new ReceiveProductBillCheck();
        check.setBillNo(bill.getNo());
        List<ReceiveProductBillCheck> checkList = receiveProductBillCheckService.selectReceiveProductBillCheckList(check);

        if (!checkList.isEmpty()) {
            // 查询物料质检信息
            List<String> productNos = checkList.stream().map(ReceiveProductBillCheck::getProductNo).distinct().collect(Collectors.toList());
            WmsProduct productParams = new WmsProduct();
            productParams.setProductNos(productNos);
            productParams.setSearchQualityItem(YNEnum.Y.getCode());
            List<WmsProduct> productList = productService.selectWmsProductList(productParams);
            Set<String> qualityProductSet = new HashSet<>();
            //先入库再检验的物料
            Set<String> waitProductSet = new HashSet<>();
            for (WmsProduct product : productList) {
                List<ProductQualityItem> productQualityItemList = this.qualityItemService.selectByPnAndQualityType(product.getProductNo(), QualityTypeEnum.IQC.getCode());
                if (CollectionUtil.isNotEmpty(productQualityItemList)) {
                    ProductQualityConfig qualityConfig = qualityConfigService.getByProductNo(product.getProductNo());
                    if (qualityConfig != null) {
                        //判断是否不入待检仓
                        if (qualityConfig.getWhetherWaitStock().intValue() == WhetherEnum.N.getCode()) {
                            qualityProductSet.add(product.getProductNo());
                        } else {
                            waitProductSet.add(product.getProductNo());
                        }
                    } else {
                        qualityProductSet.add(product.getProductNo());
                    }
                }
            }
            Map<String, List<ReceiveProductBillCheck>> checkListMap = checkList.stream()
                    .collect(Collectors.groupingBy(ReceiveProductBillCheck::getProductNo));
            //待检货入库单
            WmsInStockOrder waitInspectionStockOrder = new WmsInStockOrder();
            if (!qualityProductSet.isEmpty()) {
                long sum = checkList.stream().filter(e -> qualityProductSet.contains(e.getProductNo()))
                        .mapToLong(ReceiveProductBillCheck::getQty).sum();
                waitInspectionStockOrder.setOrderType(InStockOrderTypeEnum.WAIT_INSPECTION.getCode());
                waitInspectionStockOrder.setOrderStatus(InOrderStatusEnum.NEW.getCode());
                waitInspectionStockOrder.setRelOrderNo(bill.getNo());
                waitInspectionStockOrder.setTotalActualQty(0L);
                waitInspectionStockOrder.setTotalQty(sum);
                wmsInStockOrderService.insertWmsInStockOrder(waitInspectionStockOrder);
            }
            //收货入库单
            WmsInStockOrder stockOrder = new WmsInStockOrder();
            if (productNos.size() > qualityProductSet.size()) {
                long sum = checkList.stream().filter(e -> !qualityProductSet.contains(e.getProductNo()))
                        .mapToLong(ReceiveProductBillCheck::getQty).sum();
                stockOrder.setOrderType(InStockOrderTypeEnum.RECEIVING.getCode());
                stockOrder.setOrderStatus(InOrderStatusEnum.NEW.getCode());
                stockOrder.setRelOrderNo(bill.getNo());
                stockOrder.setTotalActualQty(0L);
                stockOrder.setTotalQty(sum);
                wmsInStockOrderService.insertWmsInStockOrder(stockOrder);
            }
            //入库单明细保存
            List<WmsInStockDetailOrder> detailList = new ArrayList(checkList.size());
            for (Map.Entry<String, List<ReceiveProductBillCheck>> entry : checkListMap.entrySet()) {
                String orderNo = qualityProductSet.contains(entry.getKey()) ?
                        waitInspectionStockOrder.getNo() : stockOrder.getNo();
                //明细初始化
                if (StringUtils.isEmpty(entry.getValue())) {
                    continue;
                }
                WmsInStockDetailOrder detailOrder = new WmsInStockDetailOrder();
                detailOrder.setProductNo(entry.getValue().get(0).getProductNo());
                detailOrder.setOrderQty(entry.getValue().stream().mapToLong(ReceiveProductBillCheck::getQty).sum());
                detailOrder.setActualQty(0L);
                detailOrder.setOrderNo(orderNo);
                detailOrder.setOrderDetailStatus(InOrderStatusEnum.NEW.getCode());
                detailOrder.setWhetherWaitProduct(waitProductSet.contains(entry.getKey()) ? WhetherEnum.Y.getCode().longValue() : WhetherEnum.N.getCode().longValue());
                detailList.add(detailOrder);
            }
            wmsInStockDetailOrderService.batchInsertInStockDetailOrder(detailList);
            //更新任务状态
            bill.setStatus(InOrderStatusEnum.ACCOMPLISH.getCode());
            bill.setCompleteTime(new Date());
        } else {
            throw new ServiceException("收货清单为空，不能完成");
        }
        return this.updateReceiveProductBill(bill);
    }

    /**
     * 确认收货单
     * @param bill    确认参数
     * @return
     */
    @Override
    public int confirm(ReceiveProductBill bill) {
        bill = this.selectReceiveProductBillById(bill.getId());
        if (bill == null) {
            throw new ServiceException("收货单不存在");
        } else if (!InOrderStatusEnum.NEW.getCode().equals(bill.getStatus())) {
            throw new ServiceException("收货单不在新建状态");
        }
        ReceiveProductBillDetail detailParams = new ReceiveProductBillDetail();
        detailParams.setBillNo(bill.getNo());
        List<ReceiveProductBillDetail> detailList = receiveProductBillDetailService.selectReceiveProductBillDetailList(detailParams);
        if (detailList.isEmpty()) {
            throw new ServiceException("该单据缺少到货单明细");
        }

        bill.setStatus(InOrderStatusEnum.PICKING.getCode());
        return this.updateReceiveProductBill(bill);
    }

    /**
     * 收货单打印
     *
     * @param no
     */
    @Override
    public ReceiveBillForPrintVO selectReceiveBillForPrint(String no) {
        return receiveProductBillMapper.selectReceiveBillForPrint(no);
    }
}
